//
//     Copyright (c) 2015 Qiwei.Gu(gqwmail@qq.com) All rights reserved.
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the sub language governing permissions and
//   limitations under the License.
//
#include "server_mgr.h"

#include <iostream>

#include "common/base/cmd_module.h"
#include "common/base/cmd_module_mgr.h"
#include "common/base/config.h"
#include "common/base/config_mgr.h"
#include "common/base/manager.h"
#include "common/base/module_mgr.h"
#include "common/base/server.h"
#include "common/base/sub_server_mgr.h"
#include "log/log.h"
#include "net/message_parse.h"
#include "net/session_mgr.h"

/**
 * @desc 初始化
 * @auth Qiwei.Gu
 * @date 2015-03-21 16:19:14
 */
bool ServerMgr::init(std::shared_ptr<ISubServerMgr> subSrvMgr)
{
    setSubServ(subSrvMgr);

    servCfg_ = std::make_shared<ServerCfg>();
    // 初始化服务器连接配置
    if (!servCfg_->init(subSrvMgr->getServerType()))
    {
        std::cerr << __FILE__ << ":" << __LINE__ << " Init Server config failed." << std::endl;
        return false;
    }

    // 初始化日志
    if (!initLog(servCfg_->getLogCfgFile()))
    {
        std::cerr << __FILE__ << ":" << __LINE__ << " Init log failed." << std::endl;
        return false;
    }

    LOG_INFO("LOG INITED.");

    const auto& configMgr = std::make_shared<ConfigMgr>();
    if (!addMgr(ManagerType::eConfig, configMgr))
    {
        LOG_ERROR("Add config manager failed.");
        return false;
    }
    // configMgr->addConfigNoInit(ConfigType(0), servCfg_);


    if (!addMgr(ManagerType::eSession, std::make_shared<SessionMgr>(getIOS(), subSrvMgr->getServerType())))
    {
        LOG_ERROR("Add session manager failed.");
        return false;
    }

    if (!addMgr(ManagerType::eModule, std::make_shared<ModuleMgr>()))
    {
        LOG_ERROR("Add module manager failed.");
        return false;
    }

    if (!addMgr(ManagerType::eCmdModule, std::make_shared<CmdModuleMgr>()))
    {
        LOG_ERROR("Add cmd module manager failed.");
        return false;
    }

    // 初始化具体的服务器
    if (!subSrvMgr_)
    {
        LOG_ERROR("Sub Server Manager NOT set.");
        return false;
    }

    if (!subSrvMgr_->init())
    {
        LOG_ERROR("Init Sub Manager server failed.");
        return false;
    }

    LOG_INFO("Init Server Manager suc.");

    // run
    run();

    return true;
}

void ServerMgr::run()
{
    // 创建IOS线程
    for (uint32_t i = 0; i < std::thread::hardware_concurrency() + 1; ++i)
    {
        std::thread t([&]{ ios_.run(); });
        iosThreads_.push_back(std::move(t));
    }

    LOG_INFO("Start run sessions ...");
    // run
    for (auto& it : iosThreads_)
    {
        it.join();
    }
}

/**
 * @desc 全局单例实现，通过它拿到其他所有资源
 * @auth Qiwei.Gu
 * @date 2015-03-21 12:23:48
 */
bool ServerMgr::addMgr(ManagerType type, std::shared_ptr<IManager> mgr)
{
    if (!mgr)
    {
        LOG_ERROR("Add null Manager not allowed.");
        return false;
    }
    mgrs_[type] = mgr;
    if (!mgr->init())
    {
        LOG_ERROR("Init Manager failed.");
        return false;
    }

    LOG_DEBUG("Add manager suc, type: " << uint32_t(type));
    return true;
}

std::shared_ptr<IManager> ServerMgr::getMgr(ManagerType type)
{
    std::lock_guard<std::mutex> lock(mutex_);

    auto it = mgrs_.find(type);
    return it == mgrs_.end() ? std::shared_ptr<IManager>() : it->second;
}

void ServerMgr::addServer(ServerType serverType, const std::shared_ptr<IServer>& server)
{
    std::lock_guard<std::mutex> lock(mutex_);

    servers_.insert(std::make_pair(serverType, server));
}

void ServerMgr::sendToServers(ServerType serverType, MessageID msgID, uint32_t sessionID,
                              const google::protobuf::Message& msg)
{
    std::lock_guard<std::mutex> lock(mutex_);
    auto ret = servers_.equal_range(serverType);
    for (auto& it = ret.first; it != ret.second; ++it)
    {
        it->second->send(msgID, sessionID, msg);
    }
}

/**
 * @desc 重新加载所有配置
 * @auth Qiwei.Gu
 * @date 2015-04-06 17:40:33
 */
bool ServerMgr::reloadConfig()
{
    auto newCfgMgr = std::make_shared<ConfigMgr>();
    if (!newCfgMgr || !newCfgMgr->init())
    {
        LOG_WARN("Create new config manager failed.");
        return false;
    }
    mgrs_[ManagerType::eConfig] = newCfgMgr;
    return true;
}

void ServerMgr::initRand()
{
    std::random_device rd;
    randEngine_.seed(rd());
}

uint16_t ServerMgr::getRandInt(uint16_t min, uint16_t max)
{
    std::uniform_int_distribution<uint16_t> dis(min, max);
    return dis(randEngine_);
}
